#include "head.h"

#include "uart2.h"
#include "stm32f10x.h"
#include "print.h"
#include "led.h"
#include "systick.h"
#include "cc9d.h"
#include "Alarm_lamp.h"
#include "Pump.h"

void localAddr_recvPkg(sCc9dPkg* recv_pkg, uint8 data_len);
/***********************************************
 * MCU使用CC9D和斥候无线模块联系，CC9D是一个简单的串口协议，可以通过串口发送和接收数据。
 * 要使用CC9D，需要添加两个c文件：
 *     cc9d.c cc9d.h
 * 包含cc9d.h头文件，此外还要实现以下两个函数：（在CC9D中，需要模块外部实现的接口函数以“_”开头）
 * 1.  void _cc9d_sendByte(uint8 b);
 *    需要发送1byte时，会调用此函数。
 * 2.  sCc9dPkg* _cc9d_receivePkg(sCc9dPkg* pkg, uint8 data_len);
 *    收到一个包时，会调用此函数。
 * 还要在使用时调用两个函数：
 * 3.cc9d_recvbyte(byte b);
 *    外部程序收到1Byte数据时，调用此函数将数据交给解码器。
 * 4.cc9d_SendPkg(sCc9dPkg* pkg, uint8 data_len);
 *    命令cc9d发送一个包，需要通过无线发送数据的时候都需要使用此函数。
***********************************************/

//1. 需要发送1byte时，会调用此函数。
void _cc9d_sendByte(uint8 b) {
	Uart2_sendByte(b);//将数据通过uart2发出
}

//2. 收到一个包时，会调用此函数。
sCc9dPkg* _cc9d_receivePkg(sCc9dPkg* pkg, uint8 data_len) {
	/***********************************************
	 * 一般情况下，收到包后需要根据目的端口号来决定如何处理数据
	 * 在程序模型中，一个嵌入式程序可能包含多个组件，
	 * 例如LED组件、电机组件、电池电量采集组件等
	 * 可以为每个需要使用无线通信的组件模块分配一个端口，
	 * 收到包后，根据目的端口号，将包交给特定的组件处理。
	 **************************************************/
	switch (pkg->to_port) {
	case AlarmLamp_PORT:
		AlarmLamp_recvPkg(pkg, data_len);
		break;
	case Pump_PORT:
		Pump_recvPkg(pkg, data_len);
		break;
	default://应该避免给模块发送目的端口号没有使用的包。
		printf("Reserved port %d get a pkg, from %X.%d\n\tdatas: ", pkg->to_port, pkg->remote_addr, pkg->from_port);
		for (int i = 0;i < data_len;i++) {
			printf("%02x ", pkg->datas[i]);
		}
		printf("\n");
		break;
	}
	//返回pkg，意味着在退出此函数后CC9D继续使用pkg接收下一个包。
	//如果程序中还要继续使用pkg中的数据，则必须准备一个未用的包指针，以供CC9D接收数据。
	return pkg;
}

//3. 此函数会不断检查串口接收缓冲，如果收到了数据，就使用cc9d_recvbyte()函数传递给CC9D。
static void checkUart2Recv() {
	int16 data;
	data = Uart2_recvByte();
	while (data != -1) {
		cc9d_recvbyte(data);
		data = Uart2_recvByte();
	}
}
static void hardBeat(){
	//发送一个心跳包报告自身存在
	sCc9dPkg send_pkg;
	send_pkg.from_port = 0;
	send_pkg.to_port = 0;
	send_pkg.remote_addr = 0;
	send_pkg.datas[0] = 'H';
	cc9d_SendPkg(&send_pkg, 1);	
}

//LED闪烁相关函数
int on_ms = 500;
int off_ms = 500;
//LED闪烁函数，在主函数循环中，每隔1ms调用一次，用于执行固定时间间隔的任务
void ledTwinkle_ms() {
	int ms_ticks = main_Clk % (on_ms + off_ms);
	if (ms_ticks == 0) {
		blueOn();
	} else if (ms_ticks == on_ms) {
		blueOff();
		ms_ticks = 0;
	}
	if (main_Clk % (7200*1000) == 3000) {
		hardBeat();
	}
}


sCc9dPkg recv_pkg_space;
int main(void) {
	//初始化各种模块
	Led_init();
	Print_init(115200);
	Uart2_init();
	Systick_init(1000);
	cc9d_init(&recv_pkg_space);
	printf("\n\n **** 斥候水泵控制 V1.0 ****\n");

	AlarmLamp_init();
	Pump_init();

	//进入主循环
	while (1) {
		if (0 != Systick_checkEventCount()) {//检查是否到了1ms。
			ledTwinkle_ms();
			Pump_msTick();
		}
		//从串口2的缓冲区中读取数据，交给CC9D解码器处理。
		checkUart2Recv();
	}
}


